#include "last_getopt_opt.h"

#include <util/stream/format.h>
#include <util/string/escape.h>
#include <util/generic/ylimits.h>
#include <util/generic/utility.h>
#include <util/generic/algorithm.h>
#include <ctype.h>

namespace NLastGetopt {


static const TStringBuf ExcludedShortNameChars = STRINGBUF("= -\t\n");
static const TStringBuf ExcludedLongNameChars = STRINGBUF("= \t\n");

bool TOpt::NameIs(const TString& name) const {
    for (const auto& next : LongNames_) {
        if (next == name)
            return true;
    }
    return false;
}

bool TOpt::CharIs(char c) const {
    for (auto next : Chars_) {
        if (next == c)
            return true;
    }
    return false;
}

char TOpt::GetChar() const {;
    if (Chars_.empty())
        ythrow TConfException() << "no char for option " << this->ToShortString();
    return Chars_.at(0);
}

char TOpt::GetCharOr0() const {
    if (Chars_.empty())
        return 0;
    return GetChar();
}

TString TOpt::GetName() const {;
    if (LongNames_.empty())
        ythrow TConfException() << "no name for option " << this->ToShortString();
    return LongNames_.at(0);
}

bool TOpt::IsAllowedShortName(unsigned char c) {
    return isprint(c) && TStringBuf::npos == ExcludedShortNameChars.find(c);
}

TOpt& TOpt::AddShortName(unsigned char c) {;
    if (!IsAllowedShortName(c))
        ythrow TUsageException() << "option char '" << c << "' is not allowed";
    Chars_.push_back(c);
    return *this;
}

bool TOpt::IsAllowedLongName(const TString& name, unsigned char* out) {
    for (size_t i = 0; i != name.size(); ++i) {
        const unsigned char c = name[i];
        if (!isprint(c) || TStringBuf::npos != ExcludedLongNameChars.find(c)) {
            if (nullptr != out)
                *out = c;
            return false;
        }
    }
    return true;
}

TOpt& TOpt::AddLongName(const TString& name) {;
    unsigned char c = 0;
    if (!IsAllowedLongName(name, &c))
        ythrow TUsageException() << "option char '" << c
            << "' in long '" << name << "' is not allowed";
    LongNames_.push_back(name);
    return *this;
}

namespace NPrivate
{
    TString OptToString(char c);

    TString OptToString(const TString& longOption);
}

TString TOpt::ToShortString() const {;
    if (!LongNames_.empty())
        return NPrivate::OptToString(LongNames_.front());
    if (!Chars_.empty())
        return NPrivate::OptToString(Chars_.front());
    return "?";
}

void TOpt::FireHandlers(const TOptsParser* parser) const {
    for (const auto& handler : Handlers_) {
        handler->HandleOpt(parser);
    }
}

}
